#pragma once
// 实现项目中一些公共的工具类接口
// 1. 生成一个唯一ID的接口
// 2. 文件的读写操作接口

#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <atomic>
#include <random>
#include <iomanip>
#include "logger.hpp"

namespace bite_im
{
    std::string uuid() 
    {
        // 生成一个由16位随机字符组成的字符串作为唯一ID
        // 1. 生成6个0~255随机数字(1字节-转换为16进制字符)--生成12位16进制字符
        std::random_device rd; // 实例化设备随机数对象-用于生成设备随机数
        std::mt19937 generator(rd());  // 以设备随机数为种子, 实例化伪随机数对象
        std::uniform_int_distribution<int> distribution(0, 255); // 限定数据范围

        std::stringstream ss;
        for(int i = 0; i < 6; i++) 
        {
            if(i == 2) ss << "-";
            // 注意它转换时比如 10 -> a， 但需要是两位0a，所以要限定宽度为2，若不为2就填充0
            ss << std::setw(2) << std::setfill('0') << std::hex << distribution(generator); 
        }
        ss << "-";
        // 2. 通过一个静态变量生成一个2字节的编号数字--生成4位16进制数字字符
        static std::atomic<short> idx(0);
        short tmp = idx.fetch_add(1);
        ss << std::setw(4) << std::setfill('0') << std::hex << tmp; 
        return ss.str();
    }

    // 随机生成手机验证码 -- dms模块因政策无法使用发送短信
    // std::string vcode() 
    // {
    //     std::random_device rd; // 实例化设备随机数对象-用于生成设备随机数
    //     std::mt19937 generator(rd());  // 以设备随机数为种子, 实例化伪随机数对象
    //     std::uniform_int_distribution<int> distribution(0, 9); // 限定数据范围

    //     std::stringstream ss;
    //     for(int i = 0; i < 4; i++) {
    //         ss << distribution(generator); 
    //     }
    //     return ss.str();
    // }

    // 用固定的
    std::string vcode(int flag = 0) 
    {
        if(flag == 0) {
            return std::string("1234");
        }
        else if(flag == 1) {
            return std::string("6666");
        }  
        else {
            return std::string("1111");
        }
    }


    bool readFile(const std::string &filename, std::string &body)
    {
        // 实现读取一个文件的所有数据，放入body中
        std::ifstream ifs(filename, std::ios::binary | std::ios::in); // 读取二进制文件
        if(ifs.is_open() == false)
        {
            LOG_ERROR("打开 {} 文件失败! ", filename);
            return false;
        }
        
        ifs.seekg(0, std::ios::end); // 跳转到文件末尾
        size_t flen = ifs.tellg();  // 获取当前偏移量 -- 文件大小
        ifs.seekg(0, std::ios::beg); // 跳转到文件起始

        body.resize(flen);
        ifs.read(&body[0], flen);
        if(ifs.good() == false)
        {
            LOG_ERROR("读取 {} 文件数据失败! ", filename);
            ifs.close();
            return false;
        }
        ifs.close();
        return true;
    }

    bool writeFile(const std::string &filename, const std::string &body)
    {
        // 实现将body中的数据，写入filename对应的文件中
        std::ofstream ofs(filename, std::ios::out | std::ios::binary | std::ios::trunc);
        if(ofs.is_open() == false)
        {
            LOG_ERROR("打开 {} 文件失败! ", filename);
            return false;
        }
        ofs.write(body.c_str(), body.size());
        if(ofs.good() == false)
        {
            LOG_ERROR("向 {} 文件写入数据失败! ", filename);
            ofs.close();
            return false;
        }
        ofs.close();
        return true;
    }
}